package com.geoai.uimap.core.mapbox

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.View
import com.geoai.uimap.api.*
import com.geoai.uimap.config.MapType
import com.geoai.uimap.core.geomap.GEOMapCustomMapStyleOptions
import com.geoai.uimap.core.geomap.GEOMapSettingsImpl
import com.geoai.uimap.core.geomap.bean.GEOMapCameraPosition
import com.geoai.uimap.model.GEOLatLng
import com.geoai.uimap.model.GEOMapException
import com.geoai.uimap.utils.toGEOLatLng
import com.mapbox.android.core.location.*
import com.mapbox.android.gestures.RotateGestureDetector
import com.mapbox.mapboxsdk.Mapbox
import com.mapbox.mapboxsdk.location.LocationComponent
import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions
import com.mapbox.mapboxsdk.location.LocationComponentOptions
import com.mapbox.mapboxsdk.location.modes.CameraMode
import com.mapbox.mapboxsdk.location.modes.RenderMode
import com.mapbox.mapboxsdk.maps.MapView
import com.mapbox.mapboxsdk.maps.MapboxMap
import com.mapbox.mapboxsdk.maps.MapboxMapOptions
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.maps.Style.OnStyleLoaded

class MapboxImpl(private val context: Context) : IGEOMap {

    companion object {
        //卫星图层
        const val SATELLITE_LAYER = "satellite_layer"
        const val SATELLITE_LAYER_ID = "satellite_layer_id"

        //高清图层
        const val HD_LAYER = "hd_layer"
        const val HD_LAYER_ID = "hd_layer_id"

        const val DEFAULT_INTERVAL_IN_MILLISECONDS = 1000L
        const val DEFAULT_MAX_WAIT_TIME = DEFAULT_INTERVAL_IN_MILLISECONDS * 5
    }

    private var style: Style? = null
    private var mapView: MapView? = null
    private var mapCamera: IGEOMapCamera? = null
    private var mapbox: MapboxMap? = null
    private var mapProjection: IGEOMapProjection? = null
    private var mapOverlayManager: IGEOMapOverlayManager? = null

    private var mapType: Int = MapType.MAP_TYPE_SATELLITE

    //地图加载
    private var mLoaderListener: GEOMapListener.OnMapLoadedListener? = null

    //地图移动
    private var mOnCameraChangeListener: GEOMapListener.OnCameraChangeListener? = null

    //地图点击
    private var mOnMapClickListener: GEOMapListener.OnMapClickListener? = null

    //地图点击
    private var mOnMapLongClickListener: GEOMapListener.OnMapLongClickListener? = null

    //地图手势
    private var mOnMapTouchListenerList = mutableListOf<GEOMapListener.OnMapTouchListener>()

    //地图Marker点击
    private var mOnMarkerClickListener: GEOMapListener.OnMarkerClickListener? = null

    //InfoWindow
    private var mInfoWindowAdapter: GEOMapListener.InfoWindowAdapter? = null

    //地图的相关UI设置
    private var mUiSettings: IGEOMapSettings? = null

    //地图加载
    private var mMapLoad: Boolean = false

    //地图定位组件
    private var locationComponent: LocationComponent? = null
    private var locationEngine: LocationEngine? = null
    private var isFirstLocation = true

    private var geometryManager: MapboxGeometryManager? = null

    override fun onCreate(bundle: Bundle?, mapType: Int) {
        this.mapType = mapType
        val mapStyle = when (mapType) {
            MapType.MAP_TYPE_NORMAL -> { Style.OUTDOORS }
            MapType.MAP_TYPE_SATELLITE -> { Style.SATELLITE }
            MapType.MAP_TYPE_SATELLITE_STREETS -> { Style.SATELLITE_STREETS }
            else -> { Style.SATELLITE }
        }
        try {
            Mapbox.getInstance(context, "pk.eyJ1IjoiY2FrZTUxMyIsImEiOiJjajg0NnJwZG8wNjRlMnJrYXN0Ymc0bGgyIn0.dhDnEcLoVeDPOK_cjFSbzg")
            val mapboxMapOptions = MapboxMapOptions.createFromAttributes(context, null)
            mapboxMapOptions.textureMode(true)
            mapView = MapView(context, mapboxMapOptions)
            mapView?.onCreate(bundle)
            mapView?.getMapAsync { mapboxMap ->
                mapbox = mapboxMap
                //加载自己的数据源
                mapboxMap.setStyle(mapStyle) {
                    if (it.isFullyLoaded) {
                        geometryManager = MapboxGeometryManager(this, mapView!!, mapboxMap)
                        initListener(mapboxMap)
                        mLoaderListener?.onMapLoaded()
                        mMapLoad = true
                        style = it
                    }
                }
                //底图
//            val imageSource = ImageSource("image_source", LatLngQuad(
//                LatLng(89.9,-180.0),
//                LatLng(89.9,180.0),
//                LatLng(-89.9,180.0),
//                LatLng(-89.9,-180.0)
//            ), R.mipmap.bg_hd_map)
//            val imageLayer = RasterLayer("image_layer-id","image_source")

//                val source = RasterSource(SATELLITE_LAYER, TileSet("tileset ", "http://agri-map.xaircraft.com/google/{z}/{x}/{y}.jpeg"), 256)
//                satelliteLayer = RasterLayer(SATELLITE_LAYER_ID, SATELLITE_LAYER)

                //高清地图
//                val guid = AccountManager.getInstance().user.guid
//                val hdSource = RasterSource(HD_LAYER, TileSet("tileset ", getHdMapUrl(guid)), 256)
//                hdLayer = RasterLayer(HD_LAYER_ID, HD_LAYER)
//                hdLayer?.setProperties(PropertyFactory.visibility(Property.NONE))

//                mapboxMap.setStyle(Style.Builder().withSources(source).withLayers(satelliteLayer)) {
//                    geometryManager = MapboxGeometryManager(this, mapView!!, mapboxMap)
//                    initListener(mapboxMap)
//                    mLoaderListener?.onMapLoaded()
//                    mMapLoad = true
//                }
                mapboxMap.uiSettings.isTiltGesturesEnabled = false
                mapboxMap.uiSettings.isAttributionEnabled = false
                mapboxMap.uiSettings.isCompassEnabled = false
                mapboxMap.uiSettings.isRotateGesturesEnabled = false
                mapboxMap.uiSettings.setLogoMargins(-1000, 0, 0, -1000)

            }
            mapCamera = MapboxCamera(this)
            mapProjection = MapboxProjection(this)
            mapOverlayManager = MapboxOverlayManager(this)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }


    fun getGeometryManager(): MapboxGeometryManager? {
        return geometryManager
    }


    @SuppressLint("ClickableViewAccessibility")
    private fun initListener(mapboxMap: MapboxMap) {
        mapboxMap.addOnCameraMoveListener {
            val geoMapCameraPosition = GEOMapCameraPosition()
            geoMapCameraPosition.bearing = mapboxMap.cameraPosition.bearing.toFloat()
            geoMapCameraPosition.zoom = mapboxMap.cameraPosition.zoom.toFloat()
            geoMapCameraPosition.target = mapboxMap.cameraPosition.target.toGEOLatLng()
            mOnCameraChangeListener?.onCameraChange(geoMapCameraPosition)
        }


        mapboxMap.addOnMapClickListener { latLng ->
            mOnMapClickListener?.onMapClick(latLng.toGEOLatLng())
            true
        }

        mapboxMap.addOnMapLongClickListener { latLng ->
            mOnMapLongClickListener?.onMapLongClick(latLng.toGEOLatLng())
            true
        }

        mapboxMap.addOnCameraIdleListener {
            val geoMapCameraPosition = GEOMapCameraPosition()
            geoMapCameraPosition.bearing = mapboxMap.cameraPosition.bearing.toFloat()
            geoMapCameraPosition.zoom = mapboxMap.cameraPosition.zoom.toFloat()
            geoMapCameraPosition.target = mapboxMap.cameraPosition.target.toGEOLatLng()
            mOnCameraChangeListener?.onCameraChangeFinish(geoMapCameraPosition)
        }



        mapboxMap.addOnCameraMoveCancelListener {
        }


        mapboxMap.addOnRotateListener(object : MapboxMap.OnRotateListener {
            override fun onRotateBegin(detector: RotateGestureDetector) {

            }

            override fun onRotate(detector: RotateGestureDetector) {

            }

            override fun onRotateEnd(detector: RotateGestureDetector) {

            }

        })

        //Marker的点击
        geometryManager?.getSymbolManager()?.addClickListener {
            mOnMarkerClickListener?.onMarkerClick(it.id.toString())
            true
        }

        mapView?.setOnTouchListener { _, motionEvent ->
            mOnMapTouchListenerList.forEach {
                it.onTouch(event = motionEvent)
            }
            false
        }
    }

    override fun onResume() {
        mapView?.onResume()
    }

    override fun onPause() {
        mapView?.onPause()
    }

    override fun onStart() {
        try {
            mapView?.onStart()
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }

    override fun onStop() {
        mapView?.onStop()
    }

    override fun onDestroy() {
        getGeometryManager()?.onDestroy()
        locationEngine?.removeLocationUpdates(locationChangeListener)
        mapView?.onDestroy()
    }

    override fun getContext(): Context {
        return context
    }

    override fun getMapView(): View {
        return mapView ?: throw GEOMapException(0x3001, "init mapbox first")
    }

    override fun getMapCamera(): IGEOMapCamera {
        return mapCamera ?: throw GEOMapException(0x3001, "init mapbox first")
    }

    override fun getMapOverlayManager(): IGEOMapOverlayManager {
        return mapOverlayManager!!
    }

    override fun getMapProjection(): IGEOMapProjection {
        return mapProjection ?: throw GEOMapException(0x3001, "init mapbox first")
    }

    override fun setMapType(type: Int) {
        mapType = type

        val builder = Style.Builder()

        style?.let {
            with(it.javaClass.getDeclaredField("images")) {
                isAccessible = true
                get(style) as HashMap<String, Bitmap>
            }.forEach { (key, bitmap) ->
                //将资源放置到新的builder中，并且手动回收Style中的资源
                builder.withImage(key, bitmap.copy(Bitmap.Config.ARGB_8888, true))
                it.removeImage(key)
                bitmap.recycle()
            }
        }

        val onStyleLoaded = OnStyleLoaded {style ->
            geometryManager?.updateStyle(style)
            this.style = style
            //将替换出的资源重新设置到Style中
            with(style.javaClass.getDeclaredField("images")) {
                isAccessible = true
                get(style) as HashMap<String, Bitmap>
            }.let {hashMap ->
                builder.images.forEach { hashMap[it.id] = it.bitmap }
            }
        }

        when (type) {
            MapType.MAP_TYPE_NORMAL -> {
                mapbox?.setStyle(builder.fromUri(Style.OUTDOORS), onStyleLoaded)
            }
            MapType.MAP_TYPE_SATELLITE -> {
                mapbox?.setStyle(builder.fromUri(Style.SATELLITE), onStyleLoaded)
            }
            MapType.MAP_TYPE_SATELLITE_STREETS -> {
                mapbox?.setStyle(builder.fromUri(Style.SATELLITE_STREETS), onStyleLoaded)
            }
        }
    }

    override fun showHdLayer(show: Boolean) {
    }

    override fun getMapType(): Int {
        return mapType
    }

    override fun isLoaded(): Boolean {
        return mMapLoad
    }

    override fun getMapUiSettings(): IGEOMapSettings? {
        if (mUiSettings == null) {
            mUiSettings = GEOMapSettingsImpl(this)
        }
        return mUiSettings
    }

    override fun setCustomMapStyle(options: GEOMapCustomMapStyleOptions) {

    }

    /**
     * 在地图加载之后调用此方法
     */
    @SuppressLint("MissingPermission")
    override fun initMapLocation(locationIcon: Int, isMyLocationEnabled: Boolean) {
        val mapBox = getMapbox()
        if (mapView == null || mapBox == null) {
            return
        }

        isFirstLocation = isMyLocationEnabled

        mapBox.getStyle {
            val customLocationComponentOptions = LocationComponentOptions.builder(context)
                    .elevation(0f)
                    .accuracyColor(Color.TRANSPARENT)
                    .backgroundTintColor(Color.TRANSPARENT)
                    .bearingDrawable(locationIcon)
//                    .layerAbove(HD_LAYER_ID)
                    .build()
            locationComponent = mapBox.locationComponent
            val locationComponentActivationOptions = LocationComponentActivationOptions.builder(context, it)
                    .locationComponentOptions(customLocationComponentOptions)
                    .build()
            locationComponent?.activateLocationComponent(locationComponentActivationOptions)
            locationComponent?.isLocationComponentEnabled = true
            locationComponent?.cameraMode = CameraMode.TRACKING
            locationComponent?.renderMode = RenderMode.COMPASS
            initLocationListener()
        }


    }

    @SuppressLint("MissingPermission")
    private fun initLocationListener() {
        locationComponent?.let {

            try {
                locationEngine = LocationEngineProvider.getBestLocationEngine(context)
                val request = LocationEngineRequest.Builder(DEFAULT_INTERVAL_IN_MILLISECONDS)
                        .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
                        .setMaxWaitTime(DEFAULT_MAX_WAIT_TIME).build()
                locationEngine?.requestLocationUpdates(request, locationChangeListener, context.mainLooper)
                locationEngine?.getLastLocation(locationChangeListener)
            } catch (e: Exception) {
            }

        }

    }


    private val locationChangeListener = object : LocationEngineCallback<LocationEngineResult> {
        override fun onSuccess(result: LocationEngineResult?) {

            val location = result?.lastLocation
            if (isFirstLocation && location != null) {
                isFirstLocation = false
                getMapCamera().setPosition(GEOLatLng(location.latitude, location.longitude), 16f)
            }
        }

        override fun onFailure(p0: Exception) {
        }

    }


    override fun moveToLocation() {
        val location = locationComponent?.lastKnownLocation
        if (location != null) {
            getMapCamera().setPosition(GEOLatLng(location.latitude, location.longitude), 16f)
        }

    }

    override fun removeCache(listener: GEOMapListener.OnCacheRemoveListener) {

    }

    override fun setOnMapLoadedListener(listener: GEOMapListener.OnMapLoadedListener) {
        mLoaderListener = listener
    }

    override fun setOnMapClickListener(listener: GEOMapListener.OnMapClickListener) {
        mOnMapClickListener = listener
    }

    override fun setOnMapLongClickListener(listener: GEOMapListener.OnMapLongClickListener) {
        mOnMapLongClickListener = listener
    }

    override fun setOnCameraChangeListener(listener: GEOMapListener.OnCameraChangeListener) {
        mOnCameraChangeListener = listener
    }

    override fun addOnMapTouchListener(listener: GEOMapListener.OnMapTouchListener) {
        mOnMapTouchListenerList.add(listener)
    }

    override fun removeOnMapTouchListener(listener: GEOMapListener.OnMapTouchListener) {
        mOnMapTouchListenerList.remove(listener)
    }

    override fun setOnMarkerClickListener(listener: GEOMapListener.OnMarkerClickListener) {
        mOnMarkerClickListener = listener
    }

    override fun getMapScreenShot(function: (Bitmap?) -> Unit) {
        mapbox?.snapshot {
            function.invoke(it)
        }
    }

    override fun setInfoWindowAdapter(listener: GEOMapListener.InfoWindowAdapter) {
        mInfoWindowAdapter = listener
    }

    fun getInfoWindowAdapter(): GEOMapListener.InfoWindowAdapter? {
        return mInfoWindowAdapter
    }

    fun getMapbox(): MapboxMap? {
        return mapbox
    }
}